/* << fastinsert report library >> PdfBase.cpp Oct 31, 2010
 *
 * 	http://code.google.com/p/libfir
 *
 * Copyright (c) 2005 Pavlo Drobov (drobov.pavel@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

#include "Debug.h"
#include <string.h>
#include <time.h>

#include "Debug.h"
#include "PdfBase.h"
#include "PdfGrid.h"
#include "hpdf_conf.h"

//matrix code for IDAutomation EAN13
#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif


#define PAGE_DEFAULT_PREFIX 		"Page "
#define PAGE_NUMERATION_SIZE		10.0f
#define PAGE_BOTTOM_FOR_SIZETEXT	10.0f
#define PAGE_FIR_PLACE				mm2pixel(A4_HIGHT,RESOLUTION_DPI) - 10.0f
#define PAGE_FIR_FONT_SIZE			10.0f
#define PAGE_FIR_TEXT				"FIR SAMPLE (http://code.google.com/p/libfir)"
#define DT_DEFAULT_PREFIX 			"creation date: "
#define PAGE_DATE_FONT_SIZE			8.0f




//default font
//#include "../fonts/arialn.h"
//#define FONT_LZMA_HEX ARIALN_ttf

//#include "../fonts/XeroxSansSerifNarrow.h"
//#define FONT_LZMA_HEX XeroxSansSerifNarrow_ttf

#include "../fonts/LiberationSansNarrow-Regular.h"
#define FONT_LZMA_HEX LiberationSansNarrow_Regular_ttf


//default fonts
//#include "../fonts/IDAutomationSUPCEANM.h"

//constant form font hex file
//#define EAN13_FONT_HEX IDAutomationSUPCEANM_ttf


#include "../aliens/quicklz/quicklz.c"


static const char*
HPDF_LoadTTFontFromBuffer(const HPDF_Doc& pdf,
						  HPDF_BYTE * fontRef,
						  size_t length
						  )
{
    HPDF_Stream font_data;
    const char *ret;

    if (!HPDF_HasDoc (pdf))
        return NULL;

    // create file stream
//    font_data = HPDF_MemStream_New(pdf->mmgr, HPDF_STREAM_BUF_SIZ);
    font_data = HPDF_MemStream_New(pdf->mmgr, length);

    //write buffer
    HPDF_Stream_Write(font_data,fontRef,length);

    ret = HPDF_Stream_Validate (font_data)
        		? LoadTTFontFromStream (pdf, font_data,HPDF_TRUE, "")
        		: NULL;

    if (!ret)
        HPDF_CheckError (&pdf->error);

    return ret;
}



namespace dasco
{
namespace report
{

//static jmp_buf env;
static void error_handler  (
				 HPDF_STATUS   error_no
				,HPDF_STATUS   detail_no
				,void          *user_data
				)
{
	char buf[0xFF];
	::sprintf(buf,
			"ERROR(error_handler): error_no=%04X, detail_no=%u"
			,(HPDF_UINT)error_no
			,(HPDF_UINT)detail_no
			);
	DEBUG_MSG(buf);
	exit(-1);
}



///////////////////////////////////////////////////////////
//const float PdfBase::A4_width = mm2pixel(140.0f,RESOLUTION_DPI);
//const float PdfBase::A4_hight = mm2pixel(200.0f,RESOLUTION_DPI);

const float PdfBase::A4_width = mm2pixel(A4_WIDTH,RESOLUTION_DPI);
const float PdfBase::A4_hight = mm2pixel(A4_HIGHT,RESOLUTION_DPI);


PdfBase::PdfBase(const char* outLine)
	:pdf(::HPDF_New(error_handler, NULL))
	,encoder(::HPDF_GetEncoder (pdf, DEFAULT_PDF_ENCODE))
	,root(::HPDF_CreateOutline (pdf, NULL, outLine, encoder))
{

	DEBUG_MSG("constructor PdfBase::PdfBase(const char*): " << outLine);
	::HPDF_SetCompressionMode (pdf, HPDF_COMP_ALL);

	::HPDF_SetCurrentEncoder(pdf,DEFAULT_PDF_ENCODE);

    // Set page mode to use outlines.
    ::HPDF_SetPageMode(pdf, HPDF_PAGE_MODE_USE_OUTLINE);
    ::HPDF_SetPageLayout(pdf, HPDF_PAGE_LAYOUT_SINGLE);
    ::HPDF_Outline_SetOpened (root, HPDF_TRUE);


/*
	//download main TTF font
	downloadQuickLzFontTTF(font
						,ARIALN_ttf //quicklz byte based dimmension
						,sizeof(ARIALN_ttf)
						);
*/

	//download main TTF font
	downloadQuickLzFontTTF(font
						,FONT_LZMA_HEX //quicklz byte based dimmension
						,sizeof(FONT_LZMA_HEX)
						);


	/*
#if 1
	//download main TTF font
	downloadQuickLzFontTTF(ean13font
						,EAN13_FONT_HEX //	quicklz byte based dimmension
						,sizeof(EAN13_FONT_HEX)
						);
#else
	ean13font = font;
#endif
*/
}

PdfBase::~PdfBase()
{
	const_iterator rabbit = begin(), race_over = end();
	while(rabbit != race_over)
		delete *rabbit++;
	::HPDF_FreeDocAll(pdf);
	::HPDF_Free(pdf);
}


void PdfBase::downloadQuickLzFontTTF(HPDF_Font& font,const unsigned char* fontHex, const unsigned fontLength,const char* encode)
{
	char *  scratch = new char[QLZ_SCRATCH_COMPRESS];
	HPDF_BYTE* unArchFont = new HPDF_BYTE[fontLength *5];

	size_t resultLength = ::qlz_decompress((const char*)fontHex, unArchFont,scratch);

	//DEBUG_MSG("$$$$$$" TAB "download QuickLzData unArch size:" << resultLength);

	const char * downLoadFontName =
			::HPDF_LoadTTFontFromBuffer (pdf
										,unArchFont
                                        ,resultLength
										);

	font = ::HPDF_GetFont (pdf
    						, downLoadFontName
    						, encode
    						);

	//DEBUG_MSG(" namefont: "  << downLoadFontName  << " ; valid: " <<  	(bool)HPDF_Font_Validate (font));

    delete [] scratch;
    delete [] unArchFont;
}


PdfPage* PdfBase::getPage()
{
	PdfPage* page = new PdfPage(pdf);
	push_back(page);
	return page;
}


void PdfBase::save(const char* filePath) throw (IIOException)
{
	HPDF_STATUS status = ::HPDF_SaveToFile(pdf, filePath);
	if(status)
		throw IIOException(status);
}


int PdfBase::getPdfSize()
{
	::HPDF_SaveToStream(pdf);
	return pdf->stream->size;
}

void PdfBase::getPdfByte(unsigned char * buf,unsigned* realSize)
{
	::HPDF_SaveToStream(pdf);
	::HPDF_ReadFromStream(pdf,buf,realSize);
//	DEBUG_MSG(" getPdfByte ==> " << (int) *realSize);
}


HPDF_Outline PdfBase::createOnline(const char* text, const HPDF_Outline& outline )
{
	return  ::HPDF_CreateOutline (pdf, outline, text, encoder);
}

/*
void PdfBase::ean13_matrix_IDAutomation(char* src,char* dst,unsigned size)
{
	::IDAutomation_EAN13(src,dst,size);
}
*/

unsigned PdfBase::measureText(const char *text,float fontSize,float  widthPage) const
{
	unsigned rc = ::HPDF_Font_MeasureText(
				font
				,(const HPDF_BYTE *)text
				,::strlen(text)
				,widthPage
				,fontSize
				,HPDF_DEF_CHARSPACE
				,HPDF_DEF_WORDSPACE
				,HPDF_FALSE
				,NULL
				);

	return rc;
}

void PdfBase::numerationPage(const char* txt)
{
	unsigned pageCnter = 1;
	unsigned length = txt ? ::strlen(txt) : sizeof(PAGE_DEFAULT_PREFIX);
	length += 0xF;

	char * buf = new char[length];

	const_iterator rabbit = begin(), race_over = end();

	while(rabbit != race_over)
	{
		::sprintf(buf,"%s  - %i -",(txt? txt : PAGE_DEFAULT_PREFIX),pageCnter++);
		PdfPage * pdfPage = *rabbit++;
		pdfPage->setFontAndSize(font,PAGE_NUMERATION_SIZE);
		pdfPage->renderText((pdfPage->getWidth() - ::strlen(buf))/2
						    ,PAGE_BOTTOM_FOR_SIZETEXT
						    ,buf);
	}

	delete [] buf;
}


void PdfBase::currentDate(const char *dtText)
{
	time_t time;
	unsigned len = dtText ? ::strlen(dtText) + 0x2F : 0xFF;
	char * midge, * buf;
	midge=buf = new char [len];

	::memcpy(midge,DT_DEFAULT_PREFIX,sizeof(DT_DEFAULT_PREFIX));

	midge += sizeof(DT_DEFAULT_PREFIX) -1;
	if(dtText)
	{
		::sprintf(midge,"%s ",dtText);
	}
	else
	{
		::time(&time);
		::strftime(midge,len - sizeof(DT_DEFAULT_PREFIX),"%d %B %Y %H:%M",localtime(&time));
	}

	//DEBUG_MSG("DATE: " << buf);
	const_iterator rabbit = begin(), race_over = end();
	while(rabbit != race_over)
	{
		PdfPage * pdfPage = *rabbit++;
		pdfPage->setFontAndSize(font,PAGE_DATE_FONT_SIZE);
		pdfPage->renderText(10.0f
							,PAGE_BOTTOM_FOR_SIZETEXT
							,buf);
	}

	delete [] buf;
}

void PdfBase::setFIRdemo()
{
	const_iterator rabbit = begin(), race_over = end();
	while(rabbit != race_over)
	{
		PdfPage * pdfPage = *rabbit++;
		pdfPage->setFontAndSize(font,PAGE_FIR_FONT_SIZE);
		pdfPage->renderText(A4_width/2.0f - sizeof(PAGE_FIR_TEXT) //Proximally  center
							,PAGE_FIR_PLACE
							,PAGE_FIR_TEXT);
	}

}


void PdfBase::renderGrid(const IGrid* iGrid)
{
	GridPdf gridPdf((IGrid*)iGrid);
	gridPdf.render(this);
}



}} //end namespace dasco::stricker

////////////////// C API ////////////////////////////////
extern "C"
{

DLL_EXPORT void helloWorld()
{
}

DLL_EXPORT void initDebug(const char* debugFilePath)
{
	Debug::getInstance(debugFilePath);
}

using namespace dasco::report;

static PdfBase * pdfBase = NULL;

DLL_EXPORT void initReport(const char* header)
{
	if (pdfBase)
	{
		delete pdfBase;
	}
	pdfBase = new PdfBase(header);
}


DLL_EXPORT HANDLE getReport()
{
	if (!pdfBase)
	{
		initReport("outline");
	}
	return pdfBase;
}

DLL_EXPORT void numerationPage(const char* txt)
{
	if (pdfBase)
		pdfBase->numerationPage(txt);
}

DLL_EXPORT void currentDate(const char* txt)
{
	if (pdfBase)
		pdfBase->currentDate(txt);
}


DLL_EXPORT void saveToFileReport(const char* filePath)
{
	if (pdfBase)
		pdfBase->save(filePath);
}

DLL_EXPORT void releaseReport()
{
	DEBUG_MSG("releaseReport: " << pdfBase);

	if (pdfBase)
	{
		delete pdfBase;
		pdfBase = NULL;
	}
}




} //end extern "C"


